<?php
/*
# $Id$
*/

/*
# @class BuanAutoLoader
#
# Static class to provide a common mechanism for loading class files.
*/
class BuanAutoLoader {

	/*
	# @property array $classPaths
	# A list of all folder paths that will be searched to find a given class	
	# file.
	*/
	static private $classPaths = array();

	/*
	# @method void loadClass( string $className )
	# $className	= Name of the class that needs to be loaded (case-sensitive)
	#
	# Attempts to find and include a source file for the specified class.
	# If not found, it throws a BuanException, which is caught and handled by
	# "__autoload()".
	*/
	static public function loadClass($className) {

		// Search all class paths
		foreach(self::$classPaths as $idx=>$path) {
			if(is_file("$path/$className.php")) {
				include_once("$path/$className.php");
				reset(self::$classPaths);
				return TRUE;
			}
		}

		// If the class wasn't found, throw a BuanException
		throw new BuanException("Class '$className' was not found.");
	}

	/*
	# @method void addClassPath( string $path )
	# $path	= Absolute path
	#
	# Adds a folder path to the list of paths to search when loading classes.
	#
	# TODO:
	# Could add another parameter here, $regex, which you could use to indicate what filename matches
	# are stored in the given path, so the searching routine would only bother searching in $path if the
	# given class name matches this $regex (if $regex is ommitted then any filename would be assumed).
	*/
	static public function addClassPath($path) {

		// Add the specified path to the list of paths to be searched when loading a class
		self::$classPaths[] = $path;
	}
}

/*
# Register a global-scoped function with the spl_autoload stack.
#
# TODO:
# The exception handling doesn't seem to work if we register
# BuanAutoLoader::loadClass() directly, but using this global function does.
# Look into why.
# Might it be the fact that this routine defines a new class within the scope of
# a class method?
*/
function fBuanAutoLoader($className) {
	try {
		BuanAutoLoader::loadClass($className);
	}
	catch(BuanException $e) {

		// Check for any other custom autoloaders that have been registered via
		// SPL and execute each one in turn in an effort to load the required
		// class.
		$customAutoloaders = array_diff(spl_autoload_functions(), array(__FUNCTION__));
		if(count($customAutoloaders)>0) {
			foreach($customAutoloaders as $al) {
				$al($className);
				if(class_exists($className, FALSE)) {
					return TRUE;
				}
			}
		}

		// If the class has still not been defined, auto-define it here.
		// This will throw the Exception message $e.
		// NOTE: The $count variable is used to ensure that the Exception is
		// only unserialized once, other we get offset errors.
		if(!class_exists($className, FALSE)) {
			$eserial = preg_replace("/\'/", "\'", serialize($e));
			return eval("class $className {
				function __construct(\$e=NULL) {
					static \$count = 0;
					\$count++;
					if(\$count==1) {
						\$e = unserialize(\$e);
						throw \$e;
					}
				}
	
				function __call(\$method, \$args) {
					SystemLog::add('Trying to call a method after class was not found, \"$className::\$method\".', SystemLog::WARNING);
				}
			}
			new $className('$eserial');");
		}
	}
	return TRUE;
}
spl_autoload_register('fBuanAutoLoader');
?>